#!/usr/bin/env perl

# Run multiple instances of the kambiz bench, and display the avg result table
# For the old behavior, see revisions <78

# For the wrekagrid project,
# Basile Clout, October 2007


use Getopt::Long;
use Statistics::Descriptive;

use strict;
use warnings;

sub usage {
  print <<EOF;

Usage: runKambiz [-n number of tests (default=1)] [-h help] [-l log_file] [-u user to run bench as] [-r res_file] <.node file> <.ele
file> <.part file> 

Launch -n number of instances of the kambiz\'s bench on the same
partition, and prints the corresponding statistics.

EOF
exit;
}

my $launch_bin="/root/export_cluster/code/tools/lauchKambiz.sh";
my $log_file = "runKambiz.log";
my $res_file = "runKambiz.res";
my $user="root";

my $nb_tests = 1;
my $help;

my ($fnode, $fele, $fpart);
GetOptions("n=i"=>\$nb_tests, "u=s"=>\$user, "h"=>\$help, "l=s"=>\$log_file, "r=s"=>\$res_file);

if ($#ARGV != 2 || $help){
  usage();
}else{
  $fnode=$ARGV[0];
  $fele=$ARGV[1];
  $fpart=$ARGV[2];
}

# Sudo with the H option to get the target HOME -- necessary for mpich2
my $mpi_line = "sudo -H -u $user $launch_bin $fnode $fele $fpart";
my $nb_parts=0;

# Open log
open LOG, ">$log_file" or die "Impossible to create $log_file: $!";
open RES, ">$res_file" or die "Impossible to create $res_file: $!";
my ($sec, $min, $hrs, $day, $month, $year) = (localtime) [0,1,2,3,4,5];
my $date = sprintf("%04d-%02d-%02d %d:%d:%d\n", $year+1900, $month+1, $day, $hrs, $min, $sec);
print LOG "# bench kambiz log, Basile Clout, $date \n\n";
print RES "# bench lambiz res, Basile Clout, generated on $date\n\n";

my @big_arr=();
my $test;

foreach $test (1 .. $nb_tests) {
  
  $nb_parts=0;
  print RES "# \@$test\n";
  print "# Test $test ...\n";
  open(BENCH, "$mpi_line |");
  my @content = <BENCH>;
  print LOG "Test $test: \n",join(' ', @content),"\n";
  
  foreach my $line (@content) {
    if ($line =~ /P(\d+)\s+(\d+\.\d+)\s+(\d+\.\d+)\s+(\d+)/) {
      $big_arr[$test][$1] = [$2, $3, $4];
      $nb_parts++;
    }
  }
  
  for (my $i=0;$i<$nb_parts;$i++) {
    print RES join(' ', @{$big_arr[$test][$i]}), "\n";
  }
}


print RES "# \@stats\n";
print "# processor computation_time communication_time cg\n";
my $stat;
my @avg_times_arr;
my @avg_comm_arr;
my @avg_cg_arr;

for my $part (0 .. $nb_parts-1) {
  
  my @cmp_arr;
  my @com_arr;
  my @cg_arr;

  for $test (0 .. $nb_tests-1) {
    $cmp_arr[$test] = $big_arr[$test+1][$part][0];
    $com_arr[$test] = $big_arr[$test+1][$part][1];
    $cg_arr[$test] = $big_arr[$test+1][$part][2];
  }

  $stat = Statistics::Descriptive::Sparse->new();
  $stat->add_data(@cmp_arr);
  my $cmp_min = $stat->min();
  my $cmp_max = $stat->max();
  my $cmp_avg = $stat->sum()/$stat->count();
  push @avg_times_arr, $cmp_avg;
  my $cmp_std;
  if ($nb_tests > 1){
      $cmp_std = $stat->standard_deviation();
  }else{
      $cmp_std = 0;
  }

  $stat = Statistics::Descriptive::Sparse->new();
  $stat->add_data(@com_arr);
  my $com_min = $stat->min();
  my $com_max = $stat->max();
  my $com_avg = $stat->sum()/$stat->count();
  push @avg_comm_arr, $com_avg;
  my $com_std;
  if ($nb_tests > 1){
      $com_std = $stat->standard_deviation();
  }else{
      $com_std = 0;
  }

  $stat = Statistics::Descriptive::Sparse->new();
  $stat->add_data(@cg_arr);
  my $cg_min = $stat->min();
  my $cg_max = $stat->max();
  my $cg_avg = $stat->sum()/$stat->count();
  push @avg_cg_arr, $cg_avg;
  my $cg_std;
  if ($nb_tests > 1){
      $cg_std = $stat->standard_deviation();
  }else{
      $cg_std = 0;
  }

  printf "%d  %.2f  %.5f  %d\n", $part, $cmp_avg, $com_avg, $cg_avg;
  printf RES "%d %.2f(%.2f %.2f %.3f) %.5f(%.5f %.5f %.3f) %d(%d %d %.3f)\n",$part, $cmp_avg, $cmp_min, $cmp_max, $cmp_std, $com_avg, $com_min, $com_max, $com_std, $cg_avg, $cg_min, $cg_max, $cg_std;	
  printf LOG "%d %.2f(%.2f %.2f %.3f) %.5f(%.5f %.5f %.3f) %d(%d %d %.3f)\n",$part, $cmp_avg, $cmp_min, $cmp_max, $cmp_std, $com_avg, $com_min, $com_max, $com_std, $cg_avg, $cg_min, $cg_max, $cg_std;	
}

$stat = Statistics::Descriptive::Sparse->new();
$stat->add_data(@avg_times_arr);
my $max_avg_time = $stat->max();
my $min_avg_time = $stat->min();
my $std_avg_time = 0;
if($nb_parts>1){
  $std_avg_time = $stat->standard_deviation();
}

$stat = Statistics::Descriptive::Sparse->new();
$stat->add_data(@avg_comm_arr);
my $max_avg_comm = $stat->max();
my $min_avg_comm = $stat->min();
my $std_avg_comm = 0;
if ($nb_parts>1){
  $std_avg_comm = $stat->standard_deviation();
}


$stat = Statistics::Descriptive::Sparse->new();
$stat->add_data(@avg_cg_arr);
my $max_avg_cg = $stat->max();
my $min_avg_cg = $stat->min();
my $std_avg_cg = 0;
if($nb_parts>1){
  $std_avg_cg = $stat->standard_deviation();
}

my $nb_line = "\@tests $nb_tests\n";
my $time_line = sprintf("\@time %.2f %.2f %.6f\n", $min_avg_time, $max_avg_time, $std_avg_time);
my $comm_line = sprintf("\@comm %.5f %.5f %.6f\n", $min_avg_comm, $max_avg_comm, $std_avg_comm);
my $cg_line = sprintf("\@cg %d %d %.2f\n", $min_avg_cg, $max_avg_cg, $std_avg_cg);


print RES $nb_line;
print LOG $nb_line;
print $nb_line;

print RES $time_line;
print LOG $time_line;
print $time_line;

print RES $comm_line;
print LOG $comm_line;
print $comm_line;

print RES $cg_line;
print LOG $cg_line;
print $cg_line;

